#include "CameraManager.hpp"
#include "TimeUtils.hpp"
#include "cbb_enc_type.h"
#include "cbb_log_api.h"
#include "make_unique.hpp"
// #include "xpack/json.h"
#include <iostream>
#include <thread>
CameraManager::CameraManager()
    : m_cameraController(std::make_unique<CameraController>()),
      m_encoderManager(std::make_unique<EncoderManager>()),
      m_transmitterManager(std::make_unique<TransmitterManager>()) {
}

CameraManager::~CameraManager() = default;

void CameraManager::initialize(const MultiCameraConfig &config) {
    m_cameraConfig = config;
    m_cameraController->initCamera(config);

    for (std::size_t i = 0; i < config.cameras.size(); i++) {
        if (!config.cameras[i].baseConfig.enable) {
            continue;
        }
        m_encoderManager->initializeEncoders(i, config.cameras[i].encoderConfigs);
        m_transmitterManager->initializeTransmitters(i, config.cameras[i].transportConfigs);
        auto fileStorageManager = std::make_unique<FileStorageManager>(i, config.cameras[i].storeConfig);
        fileStorageManager->start();
        m_fileStorageManagers.push_back(std::move(fileStorageManager));
    }
}
void CameraManager::start() {
    m_cameraController->startCapture([this](int cameraId, const CbbCameraFrame_t &frame) {
        this->processFrame(cameraId, frame);
    });
}

void CameraManager::stop() {
    m_cameraController->stopCapture();
}

void CameraManager::setSaveFileDir() {
    CbbLogInfo("setSaveFileDir");
    std::cout << "into setSaveFileDir" << std::endl;
}
void CameraManager::processFrame(int cameraId, const CbbCameraFrame_t &frame) {

    std::cout << "into processFrame" << std::endl;
    struct timeval v4l2Timestamp = frame.timestamp;
    int64_t unixTimestamp = TimeUtils::convertToUnixTimestamp(v4l2Timestamp);
    std::string formattedTime = TimeUtils::formatTimestamp(unixTimestamp);

    NetworkTransmitter *appTransmitter = m_transmitterManager->getTransmitter(cameraId, CAMERA_TRAN_TO_APP);
    NetworkTransmitter *slamTransmitter = m_transmitterManager->getTransmitter(cameraId, CAMERA_TRAN_TO_SLAM);

    CbbLogInfo("Frame captured at: %s", formattedTime.c_str());
    CbbLogInfo("Received frame from camera %d, size: %d bytes, V4L2 unixTimestamp: %ld, Real time: %s", cameraId, frame.len, unixTimestamp, formattedTime.c_str());

    std::cout << "Received frame from camera " << cameraId << ", size: " << frame.len << " bytes, V4L2 unixTimestamp: " << unixTimestamp << ", Real time: " << formattedTime << std::endl;
    // if (appTransmitter == nullptr || slamTransmitter == nullptr) {
    //     CbbLogError("Transmitter not found for camera %d", cameraId);
    //     return;
    // }

    std::vector<CbbEncoderRes_t> results;
    m_encoderManager->encodeFrame(cameraId, frame, results);

    std::cout << "Encoder results size: " << results.size() << std::endl;

    for (const auto &encoderResult : results) {

        NetworkFrameData netframeData;
        FileFrameData fileFrameData;

        netframeData.data.assign(encoderResult.res_data, encoderResult.res_data + encoderResult.len);
        netframeData.unixTimestamp = unixTimestamp;

        std::cout << "out format:" << encoderResult.out_format << std::endl;

        // fileFrameData.data.assign(encoderResult.res_data, encoderResult.res_data + encoderResult.len);
        // fileFrameData.formattedTime = formattedTime;
        // std::cout << "into jpeg" << std::endl;
        // m_fileStorageManagers[cameraId]->enqueueImage(fileFrameData);

        switch (encoderResult.out_format) {
        case 7:
            std::cout << "into h264" << std::endl;

            if(appTransmitter){
                std::cout << "into h264 send" << std::endl;
                appTransmitter->sendData(netframeData);
            }

            break;
        case 8:
            fileFrameData.data.assign(encoderResult.res_data, encoderResult.res_data + encoderResult.len);
            fileFrameData.formattedTime = formattedTime;
            std::cout << "into jpeg" << "size:" << encoderResult.len << std::endl;
            m_fileStorageManagers[cameraId]->enqueueImage(fileFrameData);

            // slamTransmitter->sendData(netframeData);

            break;
        default:
            CbbLogError("Unsupported output format: %d", encoderResult.out_format);
            break;
        }
    }
}
bool CameraManager::setStoreConfig(const CameraStoreOpt_t &config) {

    CbbLogInfo("setStoreConfig");
    CbbLogInfo("camera_id:%d,opt:%d,file_name:%s", config.camera_id, config.opt, config.file_name.c_str());
    if (config.camera_id >= m_fileStorageManagers.size()) {
        CbbLogError("Invalid camera_id: %d", config.camera_id);
        return false;
    }

    FileStorageManager *manager = m_fileStorageManagers[config.camera_id].get();
    if (!manager) {
        CbbLogError("FileStorageManager not initialized for camera_id: %d", config.camera_id);
        return false;
    }
    switch (config.opt) {
    case CAMERA_OPT_START: {
        StoreConfig storeConfig;
        storeConfig.enable = true;
        storeConfig.filePath = config.file_name;
        manager->initialize(storeConfig);
        manager->start();
    } break;
    case CAMERA_OPT_STOP: {
        manager->stop();
        break;
        return true;
    }
    default:
        CbbLogError("Unknown operation: %d", config.opt);
        return false;
    }
    return true;
}
bool CameraManager::setCameraConfig(const CameraConf_t &config) {

    CbbLogInfo("setCameraConfig");
    CbbLogInfo("camera_id:%d,format_app:%d,format_slam:%d,height:%d,width:%d,rotation:%d", config.camera_id, config.format_app, config.format_slam, config.height, config.width, config.rotation);

    if (config.camera_id >= m_cameraConfig.cameras.size()) {
        CbbLogError("Invalid camera_id: %d", config.camera_id);
        return false;
    }
    auto &cameraConfig = m_cameraConfig.cameras[config.camera_id];
    cameraConfig.baseConfig.width = config.width;
    cameraConfig.baseConfig.height = config.height;

    cameraConfig.encoderConfigs[0].out_format = config.format_app;
    cameraConfig.encoderConfigs[0].rotation = config.rotation;

    cameraConfig.encoderConfigs[1].out_format = config.format_slam;
    cameraConfig.encoderConfigs[1].rotation = config.rotation;

    if (!m_cameraController->updateCameraConfig(config.camera_id, cameraConfig)) {
        CbbLogError("Failed to update camera device config for camera %d", config.camera_id);
        return false;
    }

    for (size_t i = 0; i < cameraConfig.encoderConfigs.size(); ++i) {
        EncoderConfig encoderConfig = cameraConfig.encoderConfigs[i];
        encoderConfig.width = config.width;
        encoderConfig.height = config.height;
        encoderConfig.rotation = config.rotation;

        if (i == 0) {
            encoderConfig.out_format = config.format_app;
        } else if (i == 1) {
            encoderConfig.out_format = config.format_slam;
        }

        if (!m_encoderManager->updateEncoderConfig(config.camera_id, i, encoderConfig)) {
            CbbLogError("Failed to update encoder config for camera %d, encoder %zu", config.camera_id, i);
            return false;
        }
    }
    return true;
}

bool CameraManager::setCameraTranConfig(const CameraTranConf_t &config) {
    CbbLogInfo("setCameraTranConfig");

    if (config.camera_id < 0 || config.camera_id >= m_cameraConfig.cameras.size()) {
        CbbLogError("Invalid camera_id: %d", config.camera_id);
        return false;
    }
    CameraTranDirectionE_t direction = static_cast<CameraTranDirectionE_t>(config.direction);

    if (direction != CAMERA_TRAN_TO_APP && direction != CAMERA_TRAN_TO_SLAM) {
        CbbLogError("Invalid direction: %d for camera_id: %d", config.direction, config.camera_id);
        return false;
    }

    auto &transportConfig = m_cameraConfig.cameras[config.camera_id].transportConfigs[config.direction];

    // 更新配置
    transportConfig.enable = true;
    transportConfig.address = config.ip;
    transportConfig.port = config.port;
    transportConfig.protocol = config.protocol;

    CbbLogInfo("Updated transport config: ip:%s", transportConfig.address.c_str());
    // 获取对应的 NetworkTransmitter
    NetworkTransmitter *transmitter = m_transmitterManager->getTransmitter(config.camera_id, direction);

    if (!transmitter) {
        CbbLogError("Failed to get transmitter for camera_id: %d, direction: %d", config.camera_id, direction);
        return false;
    }
    transmitter->updateConfig(transportConfig);

    // 根据操作类型处理
    switch (config.opt) {
    case CAMERA_OPT_START:
        transmitter->start();
        break;
    case CAMERA_OPT_STOP:
        transmitter->stop();
        break;
    default:
        CbbLogError("Unsupported operation: %d", config.opt);
        return false;
    }

    CbbLogInfo("Updated transport config for camera_id: %d, direction: %d, ip: %s, port: %d",
               config.camera_id, config.direction, config.ip.c_str(), config.port);

    return true;
}
bool CameraManager::saveConfig() {
    // std::string json = xpack::json::encode(m_cameraConfig);

    // std::ofstream file(CAMERA_MANAGE_CONFIG_FILE_PATH);
    // if (!file.is_open()) {
    //     std::cerr << "Failed to open config file for writing: " << CAMERA_MANAGE_CONFIG_FILE_PATH << std::endl;
    //     return false;
    // }

    // file << json;
    // file.close();

    return true;
}
